<?php
/**
 * Created by PhpStorm.
 * User: xmy
 * Date: 18-7-4
 * Time: 上午8:03
 */

namespace vola;


class Route
{
    private $config = [];
    private $routelist = [];
    private static $copy;

    public function __construct()
    {
        if (empty(self::$copy)) {
            self::$copy = $this;
        }
    }

    public function register($route, $function = '', $method = '*', array $args = []) {
        if (is_array($route)) {
            foreach ($route as $name => $val) {
                // 批量注册
                $this->parseaRoute($name, $val);
            }
        } else {
            // 单列注册
            $this->parseRoute($route, $function, $method, $args);
        }

        // var_dump($this->config, $this->routelist);
    }

    /**
     * 单路由注册
     */
    private function parseRoute($route, $function = '', $method = '*', array $args = []) {
        $route = trim($route, '/');
        if (is_array($function)) {
            $this->parseaRoute($route, $function);
        } else {

            $argv = [];

            if (strpos($route, '{') !== false) {

                $route = preg_replace_callback('/\/\{(.*?)\}/i', function ($match) use (&$argv, $args) {
                    // echo $match[0];
                    $match = trim($match[1]);
                    $need = true;
                    if (strpos($match, '?') === 0) {
                        $match = trim($match, '?');
                        $need = false;
                    }
                    $argv[$match] = [
                        'isNeed' => $need,
                        'reg' => $args[$match]
                    ];
                    return '';
                }, $route);
            }

            $key = $route[0];
            $link = $route;
            $route = explode('/', $route);

            if (!isset($this->routelist[$key])) {
                $this->routelist[$key] = [];
            }
            $temp = &$this->routelist[$key];
            $route = array_filter($route);
            foreach ($route as $key) {
                if (empty($key)) {

                }
                if (!isset($temp[$key])) {
                    $temp[$key] = [];
                }
                $temp = &$temp[$key];
            }
            $temp['#'] = $function;
            unset($temp);
            $this->config[$function] = [
                'function' => $function,
                'method'   => $method,
                'args'     => $argv,
                'routelink' => $link
            ];
        }
    }

    /**
     * 多路由注册
     */
    private function parseaRoute($name, $config = '') {
        if (!is_array($config)) {
            $this->parseRoute($name, $config);
        } else {
            foreach ($config as $key => $value) {
                if (is_numeric($key)) {
                    $this->parseRoute($name, $config[0], $config[1] ? $config[1] : '*', $config[2] ? $config[2] : []);
                    break;
                }

                if (strpos($key, '/') === 0) {
                    $route = trim($name , '/') . '/' . trim($key, '/');
                } else {
                    $route = $name . '/' . $key . '/';
                }

                if (is_string($value)) {
                    $this->parseRoute($route, $value);
                } else {
                    if (is_array($value) && isset($value[0])) {
                        $value[1] = $value[1] ? $value[1] : '*';
                        $value[2] = $value[2] ? $value[2] : [];
                        $this->parseRoute($route, $value[0], $value[1], $value[2]);
                    } else {
                        $this->parseRoute($route, $value);
                    }
                }
            }
        }
    }


    public function listen($url= '', array $base = []) {
        $url = trim($url, '/');
        if (empty($url)) {
            $url = ':home';
        }
        $url = explode('/', $url);

        if (isset($this->routelist[$url[0][0]])) {
            $temp = $this->routelist[$url[0][0]];
            foreach ($url as $key => $v) {
                if (isset($temp[$v])) {
                    $temp = $temp[$v];
                    array_shift($url);
                } else {
                    break;
                }
            }
            if (isset($temp['#'])) {
                $config = $this->config[$temp['#']];
            }
        }

        if (empty($config)) {
            if ($url[0] == ':home' ) {
                array_shift($url);
            }
            if (count($url) < 3 && !empty($base)) {
                foreach ($base as $key => $v) {
                    if (empty($url)) {
                        break;
                    }
                    $base[2 - $key] = array_shift($url);
                }
            } else {
                $base = array_splice($url, 0, 3);
            }

            $config = [
                'function' => implode('/', $base),
                'method'   => '*',
                'args'     => []
            ];
        }

        $args = [];
        if (!empty($config['args'])) {
            foreach ($config['args'] as $k => $v) {
                if ($v['isNeed'] && empty($url)) {
                    Error::the('Route', 'not found args');
                }

                if (empty($url)) {
                    break;
                }
                $data = array_shift($url);
                if (preg_match('/' . $v['reg']. '/i', $data)) {
                    $args[$k] = $data;
                    Container::get('request')->get($k, $data);
                } else {
                    if ($v['isNeed']) {
                        Error::the('Route', 'Error Type args');
                    } else {
                        array_unshift($url, $data);
                    }
                }
            }
        }

        if (!empty($url)) {
            $temp = '';

            foreach ($url as $key => $v) {
                if ($key % 2 == 0) {
                    $temp = $v;
                } else {
                    Container::get('request')->get($temp, $v);
                    $temp = '';
                }
            }
        }


        return [
            'function' => $config['function'],
            'args' => $args
        ];
    }

    public function search($c, $args = []) {
        $baselink = $c;
        if (isset($this->config[$c])) {
            $route = $this->config[$c];
            $baselink = $route['routelink'];

            if (!empty($args)) {
                if (!empty($route['args'])) {
                    foreach ($route['args'] as $k => $v) {
                        if ($v['isNeed'] && !isset($args[$k])) {
                            Error::the('Route', 'not found args');
                        }

                        $data = $args[$k];
                        if (preg_match('/' . $v['reg']. '/', $data)) {
                            $baselink .= '/' . $data;
                            unset($args[$k]);
                        } else {
                            if ($v['isNeed']) {
                                Error::the('Route', 'Error Type args');
                            } else {
                                array_unshift($url, $data);
                            }
                        }
                    }
                }
            }
        }

        if (!empty($args)) {
            foreach ($args as $k => $v) {
                $baselink .= '/' . $k . '/' . $v;
            }
        }

        return $baselink;
    }

    public function run($function, $args = []) {
        echo $function . PHP_EOL;
    }

    public static function __callStatic($name, $arguments)
    {
        // TODO: Implement __callStatic() method.
        if (empty(self::$copy)) {
            new static();
        }

        return call_user_func_array([self::$copy, $name], $arguments);
    }
}
